/**********************************************************************

  Audacity: A Digital Audio Editor

  Project.h

  Dominic Mazzoni

**********************************************************************/

#ifndef __AUDACITY_PROJECT__
#define __AUDACITY_PROJECT__

#include "ClientData.h" // to inherit
#include "GlobalVariable.h"

#include <memory>
#include <mutex>

#include <wx/event.h>
using FilePath = wxString;

class AudacityProject;

//! Like a standard library container of all open projects.
//! @invariant pointers accessible through the iterators are not null
/*!
So you can iterate easily over shared pointers to them with range-for :
for (auto pProject : AllProjects{}) { ... }
The pointers are never null.

However iterators will be invalid if addition or deletion of projects occur
during traversal.
*/
class PROJECT_API AllProjects
{
    // Use shared_ptr to projects, because elsewhere we need weak_ptr
    using AProjectHolder = std::shared_ptr< AudacityProject >;
    using Container = std::vector< AProjectHolder >;
    static Container gAudacityProjects;

public:
    AllProjects() = default;

    size_t size() const;
    bool empty() const { return size() == 0; }

    using const_iterator = Container::const_iterator;
    const_iterator begin() const;
    const_iterator end() const;

    using const_reverse_iterator = Container::const_reverse_iterator;
    const_reverse_iterator rbegin() const;
    const_reverse_iterator rend() const;

    using value_type = Container::value_type;

    // If the project is present, remove it from the global array and return
    // a shared pointer, else return null.  This invalidates any iterators.
    value_type Remove(AudacityProject& project);

    //! This invalidates iterators
    /*!
     @pre pProject is not null
     */
    void Add(const value_type& pProject);

    /// In case you must iterate in a non-main thread, use this to prevent
    /// changes in the set of open projects
    static std::mutex& Mutex();
};

// Container of various objects associated with the project, which is
// responsible for destroying them
using AttachedProjectObjects = ClientData::Site<
    AudacityProject, ClientData::Base, ClientData::SkipCopying, std::shared_ptr
    >;

///\brief The top-level handle to an Audacity project.  It serves as a source
/// of events that other objects can bind to, and a container of associated
/// sub-objects that it treats opaquely.  It stores a filename and a status
/// message and a few other things.
/// There is very little in this class, most of the intelligence residing in
/// the cooperating attached objects.
class PROJECT_API AudacityProject final : public wxEvtHandler, public AttachedProjectObjects,
    public std::enable_shared_from_this<AudacityProject>
{
    struct CreateToken {};
public:
    using AttachedObjects = ::AttachedProjectObjects;

    //! Use this factory function
    static std::shared_ptr<AudacityProject> Create();
    //! Don't use this constructor directly
    AudacityProject(CreateToken);
    virtual ~AudacityProject();

    int GetProjectNumber() { return mProjectNo; }

    // Project name can be either empty or have the name of the project.
    //
    // If empty, it signifies that the project is empty/unmodified or
    // that the project hasn't yet been saved to a permanent project
    // file.
    //
    // If a name has been assigned, it is merely used to identify
    // the project and should not be used for any other purposes.
    const wxString& GetProjectName() const;
    void SetProjectName(const wxString& name);

    // Used exclusively in batch mode, this allows commands to remember
    // and use the initial import path
    FilePath GetInitialImportPath() const;
    void SetInitialImportPath(const FilePath& path);

private:

    // The project's name
    wxString mName;

    static int mProjectCounter;// global counter.
    int mProjectNo; // count when this project was created.

    FilePath mInitialImportPath;

public:
    bool mbBusyImporting{ false }; // used to fix bug 584
    int mBatchMode{ 0 };// 0 means not, >0 means in batch mode.
};

// Generate a registry for serialized data attached to the project
#include "XMLMethodRegistry.h"
class AudacityProject;
using ProjectFileIORegistry = XMLMethodRegistry<AudacityProject>;
DECLARE_XML_METHOD_REGISTRY(PROJECT_API, ProjectFileIORegistry);

namespace BasicUI {
class WindowPlacement;
}

//! Type of function that makes a WindowPlacement for dialogs, with project frame as parent
using WindowPlacementFactory = GlobalHook< AudacityProject,
                                           std::unique_ptr<const BasicUI::WindowPlacement>(
                                               AudacityProject& project)
                                           >;

//! Make a WindowPlacement object suitable for `project` (which may be null)
/*! @post return value is not null */
PROJECT_API std::unique_ptr<const BasicUI::WindowPlacement>
ProjectFramePlacement(AudacityProject* project);

#endif
